//
//  UncaughtExceptionHandler.m
//  AudioVideo
//
//  Created by xueshan1 on 2019/11/12.
//  Copyright © 2019 xueshan1. All rights reserved.
//

#import "UncaughtExceptionHandler.h"
#include <libkern/OSAtomic.h>
#include <execinfo.h>

NSString * const YunUncaughtExceptionHandlerSignalExceptionName = @"YunUncaughtExceptionHandlerSignalExceptionName";
NSString * const YunUncaughtExceptionHandlerSignalKey = @"YunUncaughtExceptionHandlerSignalKey";
NSString * const YunUncaughtExceptionHandlerAddressesKey = @"YunUncaughtExceptionHandlerAddressesKey";
//volatile的作用是作为指令关键字，确保本条指令不会因编译器的优化而省略，且要求每次直接读值。
//当前处理的异常个数
volatile int32_t YunUncaughtExceptionCount = 0;
//最大能够处理的异常个数
const int32_t YunUncaughtExceptionMaximum = 10;

const NSInteger YunUncaughtExceptionHandlerSkipAddressCount = 4;
const NSInteger YunUncaughtExceptionHandlerReportAddressCount = 5;


@implementation UncaughtExceptionHandler


//回溯, 追踪
+ (NSArray *)backtrace
{
//    backtrace函数用于获取堆栈的地址信息，
//    backtrace_symbols函数把堆栈地址翻译成我们易识别的字符串，
//    backtrace_symbols_fd函数则把字符串堆栈信息输出到文件中
     void* callstack[128];
     int frames = backtrace(callstack, 128);
     char **strs = backtrace_symbols(callstack, frames);
     
     int i;
     NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
     for (
         i = YunUncaughtExceptionHandlerSkipAddressCount;
         i < YunUncaughtExceptionHandlerSkipAddressCount +
            YunUncaughtExceptionHandlerReportAddressCount;
        i++)
     {
         [backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
     }
     free(strs);
     
     return backtrace;
}

- (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex{
    if (anIndex == 0)
    {
        dismissed = YES;
    }
}
 
//错误日志开始发送到服务器
- (void)handleException:(NSException *)exception
{
 
//    UIAlertView *alert =
//        [[UIAlertView alloc]
//            initWithTitle:NSLocalizedString(@"Unhandled exception", nil)
//            message:[NSString stringWithFormat:NSLocalizedString(
//                @"You can try to continue but the application may be unstable.\n\n"
//                @"Debug details follow:\n%@\n%@", nil),
//                [exception reason],
//                [[exception userInfo] objectForKey:YunUncaughtExceptionHandlerAddressesKey]]
//            delegate:self
//            cancelButtonTitle:NSLocalizedString(@"Quit", nil)
//            otherButtonTitles:NSLocalizedString(@"Continue", nil), nil];
//    [alert show];
    
    NSString *errorStr = [NSString stringWithFormat:NSLocalizedString(
                                                                      @"error info details follow:%@%@", nil),
                          [exception reason],
                          [[exception userInfo] objectForKey:YunUncaughtExceptionHandlerAddressesKey]]
    ;
    
   
    if(errorStr){
        [self sendErrorMsg];

        [[XSFMDBManger instance]insertErrorLog:[exception reason]];
    }
    NSLog(@"捕获的异常:error:%@",errorStr);

    //当接收到异常处理消息时，让程序开始runloop，防止程序死亡
    CFRunLoopRef runLoop = CFRunLoopGetCurrent();
    CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
    
    while (!dismissed)
    {
        for (NSString *mode in (__bridge  NSArray *)allModes)
        {
            CFRunLoopRunInMode((__bridge CFStringRef)mode, 0.001, false);
        }
    }
    
    CFRelease(allModes);

    NSSetUncaughtExceptionHandler(NULL);
    signal(SIGABRT, SIG_DFL);
    signal(SIGILL, SIG_DFL);
    signal(SIGSEGV, SIG_DFL);
    signal(SIGFPE, SIG_DFL);
    signal(SIGBUS, SIG_DFL);
    signal(SIGPIPE, SIG_DFL);
    
    if ([[exception name] isEqual:YunUncaughtExceptionHandlerSignalExceptionName])
    {
//如果我想程序发一个SIGINT函数，可以使用kill函数 kill(getpid(),SIGINT)。getpid()获得了当前运行的程序id,此时就发送了SIGINT信号给该进程
        kill(getpid(), [[[exception userInfo] objectForKey:YunUncaughtExceptionHandlerSignalKey] intValue]);
    }else{
　　　　//抛出异常,并导致崩溃
        [exception raise];
    }
}


-(void)sendErrorMsg{
    
    
 
}


@end


/**
 异常回调函数
 */
void HandleException(NSException *exception){
    //OSAtomicIncrement32：一个自增函数，在库<libkern/OSAtomic.h>中，是线程安全的；
    int32_t exceptionCount = OSAtomicIncrement32(&YunUncaughtExceptionCount);
    if (exceptionCount > YunUncaughtExceptionMaximum)
    {
        return;
    }
    
    NSArray *callStack = [UncaughtExceptionHandler backtrace];
    NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary:[exception userInfo]];
    [userInfo setObject:callStack forKey:YunUncaughtExceptionHandlerAddressesKey];
    
    [[[UncaughtExceptionHandler alloc] init] performSelectorOnMainThread:@selector(handleException:) withObject:
            [NSException exceptionWithName:[exception name] reason:[exception reason] userInfo:userInfo]     waitUntilDone:YES];
}

/**
  捕获信号后的回调函数
 */
void SignalHandler(int signal)
{
    int32_t exceptionCount = OSAtomicIncrement32(&YunUncaughtExceptionCount);
    if (exceptionCount > YunUncaughtExceptionMaximum)
    {
        return;
    }
    
    NSMutableDictionary *userInfo =
        [NSMutableDictionary
            dictionaryWithObject:[NSNumber numberWithInt:signal]
            forKey:YunUncaughtExceptionHandlerSignalKey];

    NSArray *callStack = [UncaughtExceptionHandler backtrace];
    [userInfo
        setObject:callStack
        forKey:YunUncaughtExceptionHandlerAddressesKey];
    
    [[[UncaughtExceptionHandler alloc] init]
        performSelectorOnMainThread:@selector(handleException:)
        withObject:
            [NSException
                exceptionWithName:YunUncaughtExceptionHandlerSignalExceptionName
                reason:
                    [NSString stringWithFormat:
                        NSLocalizedString(@"Signal %d was raised.", nil),
                        signal]
                userInfo:
                    [NSDictionary
                        dictionaryWithObject:[NSNumber numberWithInt:signal]
                        forKey:YunUncaughtExceptionHandlerSignalKey]]
        waitUntilDone:YES];
}

//begin
void YunInstallUncaughtExceptionHandler(void)
{
    //崩溃报告系统会用NSSetUncaughtExceptionHandler方法设置全局的 异常处理器。
    
    NSSetUncaughtExceptionHandler(&HandleException);
    signal(SIGABRT, SignalHandler);
    signal(SIGILL, SignalHandler);
    signal(SIGSEGV, SignalHandler);
    signal(SIGFPE, SignalHandler);
    signal(SIGBUS, SignalHandler);
    signal(SIGPIPE, SignalHandler);
}

/*
 
 
 SIGABRT--程序中止命令中止信号
 SIGALRM--程序超时信号
 SIGFPE--程序浮点异常信号
 SIGILL--程序非法指令信号
 SIGHUP--程序终端中止信号
 SIGINT--程序键盘中断信号
 SIGKILL--程序结束接收中止信号
 SIGTERM--程序kill中止信号
 SIGSTOP--程序键盘中止信号
 SIGSEGV--程序无效内存中止信号
 SIGBUS--程序内存字节未对齐中止信号
 SIGPIPE--程序Socket发送失败中止信号


 */
 
